package es.uji.viselab.image.source;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TimerTask;

import javax.swing.JPanel;
import javax.vecmath.Vector3d;

import es.uji.viselab.ViSeLabComponent;
import es.uji.viselab.experiment.ExperimentParameters;
import es.uji.viselab.image.camera.CameraCatalog;
import es.uji.viselab.image.process.ImageProcessCatalog;
import es.uji.viselab.image.process.ImageProcessing;
import es.uji.viselab.image.process.ProcessChessBoard;
import es.uji.viselab.math.Matrix4;
import es.uji.viselab.math.Vector2;
import es.uji.viselab.math.Vector3;
import es.uji.viselab.model.ModelCreator;
import es.uji.viselab.robot.Robot;
import es.uji.viselab.robot.RobotListener;
import es.uji.viselab.world.World;
import es.uji.viselab.world.WorldListener;

public abstract class ImageSource extends TimerTask implements RobotListener, WorldListener, ViSeLabComponent {

	private Set<ImageListener> notifiers = new HashSet<ImageListener>();
	protected ExperimentParameters ep;
	protected ArrayList<Vector2[]> ImagePointListList;

	protected Vector2[] targetPointList;
	protected Vector2[] imagePointList;
	protected Vector2[] targetCoordinateList;
	protected Vector2[] imageCoordinateList;
	protected ImageProcessing processor;

	public ImageSource(ExperimentParameters ep) {
		this.ep = ep;
		targetCoordinateList = ModelCreator.get2d(ep.getModel(), ep.getCamParameters());
		targetPointList = convertXYtoUV(targetCoordinateList);
		this.ImagePointListList = new ArrayList<Vector2[]>();
		ImageProcessCatalog imageProcessorCatalog = ep.getImageProcessor();
		switch (imageProcessorCatalog) {
		case OPENCVCHESSBOARD:
			processor = new ProcessChessBoard();
			break;
		case VIRTUAL:
			processor = null;
			break;
		}

	}

	public void setProcessing(ImageProcessing processor) {
		this.processor = processor;
	}

	public void addListener(ImageListener il) {
		notifiers.add(il);
	}

	protected void notifyFeaturePointsChange(ImageSource i) {
		Iterator<ImageListener> ili = notifiers.iterator();

		while (ili.hasNext()) {
			ImageListener il = ili.next();
			il.cameraFeaturePointsChanged(i);
		}
	}

	public Vector2[] getImageCoordinateList() {
		return imageCoordinateList;
	}

	public abstract JPanel getPanel();

	protected Vector2[] convertXYtoUV(Vector2[] xy) {
		CameraCatalog camParams = ep.getCamParameters();
		Vector2[] uv = new Vector2[xy.length];
		for (int i = 0; i < xy.length; i++) {
			double u = camParams.getImageWidth() / 2 + xy[i].x;
			double v = camParams.getImageHeight() / 2 - xy[i].y;
			uv[i] = new Vector2((int) u, (int) v);
		}
		return uv;
	}

	protected Vector2[] convertUVtoXY(Vector2[] uv) {
		CameraCatalog camParams = ep.getCamParameters();
		Vector2[] xy = new Vector2[uv.length];
		for (int i = 0; i < uv.length; i++) {
			double x = -camParams.getImageWidth() / 2 + uv[i].x;
			double y = camParams.getImageHeight() / 2 - uv[i].y;
			xy[i] = new Vector2((int) x, (int) y);
		}
		return xy;
	}

	@Override
	public void robotCreated(Robot robot) {
	}

	@Override
	public void robotDisconnected() {
	}

	@Override
	public void robotPositionChanged(Robot robot) {
	}

	@Override
	public void robotConnected(Robot robot) {
	}

	@Override
	public void worldChanged(World world) {
	}

	public Vector2[] getTargetCoordinateList() {
		return targetCoordinateList;
	}

}
